package org.yu.lemon.platform.common.exception.handler;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.xml.bind.ValidationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.yu.lemon.platform.common.constant.SymbolConstants;
import org.yu.lemon.platform.common.domain.Result;
import org.yu.lemon.platform.common.domain.ResultCodeEnum;
import org.yu.lemon.platform.common.exception.BaseException;

import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {BindException.class, ValidationException.class, MethodArgumentNotValidException.class})
    public ResponseEntity<Result<String>> handleValidatedException(@NonNull HttpServletRequest req, Exception e) {
        log.error("PARAMS VALIDATED EXCEPTION! GET REQUEST URI : {}", req.getRequestURI());
        if (e instanceof MethodArgumentNotValidException ex) {
            // BeanValidation exception
            return new ResponseEntity<>(Result.fail(HttpStatus.BAD_REQUEST.value(),
                    ex.getBindingResult().getAllErrors().stream()
                            .map(ObjectError::getDefaultMessage)
                            .collect(Collectors.joining(SymbolConstants.SEMICOLON))
            ),HttpStatus.BAD_REQUEST);
        }
        if (e instanceof ConstraintViolationException ex) {
            // BeanValidation GET simple param
            return new ResponseEntity<>(Result.fail(HttpStatus.BAD_REQUEST.value(),
                    ex.getConstraintViolations().stream()
                            .map(ConstraintViolation::getMessage)
                            .collect(Collectors.joining(SymbolConstants.SEMICOLON))
            ),HttpStatus.BAD_REQUEST);
        }
        if (e instanceof BindException ex) {
            // BeanValidation GET object param
            return new ResponseEntity<>(Result.fail(HttpStatus.BAD_REQUEST.value(),
                    ex.getAllErrors().stream()
                            .map(ObjectError::getDefaultMessage)
                            .collect(Collectors.joining(SymbolConstants.SEMICOLON))
            ),HttpStatus.BAD_REQUEST);
        }
        return new ResponseEntity<>(null,HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler({BaseException.class})
    public Result<Object> baseExceptionHandler(@NonNull HttpServletRequest req, BaseException ex) {
        log.error("BUSINESS EXCEPTION! GET REQUEST URI : {}", req.getRequestURI());
        log.error("errorCode : {}", ex.getErrorCode(), ex);
        return new Result<>(ex.getErrorCode(), ex.getMessage());
    }

    @ExceptionHandler({Exception.class})
    public Result<Object> baseExceptionHandler(@NonNull HttpServletRequest req, Exception ex) {
        log.error("ERROR! GET REQUEST URI : {}", req.getRequestURI());
        log.error(ex.getMessage(), ex);
        return new Result<>(ResultCodeEnum.SYSTEM_ERROR);
    }
}
